<html>
    <head>
    	<title>CS61C Spring 2008 -- Project 1</title>
    	<LINK REL=StyleSheet HREF="proj1.css" TYPE="text/css" MEDIA="screen, print">
	</head>

	<body>
		<div id="frame">
			<center>
				<b>
					University of California at Berkeley<br>
					College of Engineering<br>
					Department of Electrical Engineering and Computer Science<br>
				</b>
				<p>CS 61C, Spring 2008</p>

				<p><h2>Project 1 &mdash; World of 61C AdventureCraftHack</h2></p>
				<p><b><font color="#0000AA">Due Saturday, February 16th @ 11:59pm</font></b></p>
				<p><b><font color="#000000" style="BACKGROUND-COLOR: yellow">Last Updated 2/10 @ 6:30pm</font></b></p>
				<p><b><font color="#0000AA">TAs: <a href="mailto:mattjohnson@berkeley.edu">Matt Johnson</a> and <a href="mailto:casey@rodarmor.com">Casey Rodarmor</a></font></b></p>
				<p></p>
                </center>

<p><b>Yet Another Note:</b> The files you'll need for proj1 are available in <a href="cs61c_proj1.tar.gz">this archive</a>.</p>

<p><b>Another Note:</b> To be sure that you're using the correct game files, check out the newly updated <a href="#playing">Playing the Game</a> section.</p>

<p><b>Note:</b> If you're having trouble compiling, make sure you have the latest version of the code.</p>
				
<pre id="toc">
<a href="#overview">Project Overview</a>
<a href="#starting">Getting Started</a>
    <a href="#files">File Summary</a>
    <a href="#playing">Playing the Game</a>
<a href="#assignment">Assignment</a>
    <a href="#part0">Part 0: Let there be rooms!</a>
        <a href="#fileformat">Level File Format</a>
    <a href="#part1">Part 1: Get go()-ing!</a>
    <a href="#part2">Part 2: Monster Mash_t</a>
    <a href="#part3">Part 3: Magic</a>
<a href="#survival">Survival Tips</a>
    <a href="#svn">Mini SVN Tutorial</a>
<a href="#submission">Submission</a>
<a href="#efe">Extra for Experts</a>
</pre>

				<a name="overview"></a>
				<h2>Project Overview</h2>

				<p>The usual story with video games is that there are programmers who play the game and gamers who play the game&mdash;the two parties and their actions are completely separate. But for this project game, programming the game is part of playing it! To progress through the game world you will need to implement game features, and every feature you complete will allow you to progress further. After you complete each part of the assignment, you should try playing the game to explore how far you can get.</p>

				<p>We made this brand new project because other 61C projects have been seriously lacking in FUN! And what's more fun than an adventure game?! We've done our best to make this framework simple and extensible, and we hope that you'll have fun creating new monsters, spells, and levels; and even adding new features!</p>

				<p>Wow. I am super excited. Are you? Awesome. Let's move on and check out the framework that you'll build on.</p>

				<a name="starting"></a>
				<h2>Getting Started</h2>
				
				<p>The first step is to copy the game framework files into your home directory:</p>

<p>
<pre id="terminal">
    cs61c-tm@quasar ~ > <b>cp -r ~cs61c/proj/01/ ~/proj1</b>
    cs61c-tm@quasar ~ > <b>cd proj1</b>
    cs61c-tm@quasar ~/proj1 > <b>ls</b>
    Makefile        cs61c-world.lvl globals.h       monsters.c      testworld.lvl 
    commands.c      game.c          level.c         monsters.h      util.c
    commands.h      game.h          level.h         obj             util.h
    common.h        globals.c       main.c          puzzles.o      
</pre>
</p>

				<a name="files"></a>
				<h3>File Summary</h3>
				<p>Here's a short description of each file, with the ones you'll need to edit in bold:</p>
				
				<p>
				<ul>
				<li> Makefile -- contains compilation directives. Run <code>gmake</code> to build your project with the directives in Makefile. Make sure you take a look inside, we've given you a few useful shortcuts. For instance, try <code>gmake debug</code>.
				<li> obj -- By default, the Makefile puts compiled object files in this directory.
				<li> common.h -- Contains header files used throughout the project, so that we don't have to include them individually.
				<li> globals.c -- Global variable definitions, specifically <code>room_array</code>, <code>num_rooms</code>, and <code>the_player</code>. Declarations are in globals.h
				<li> main.c -- Contains the main read-eval-print loop.
				<li> util.c and util.h -- A few random utility functions that don't belong anywhere else.
				<li> <b>level.c</b> and level.h -- Contains functions and structs related to level loading.
				<li> <b>commands.c</b> and commands.h -- All the in-game commands are implemented here. A sweet example of data-directed programming with function pointers!
				<li> <b>game.c</b> and game.h -- Lots of game related game internals, including magic, damage, and experience functions.
				<li> <b>monsters.c</b> and <b>monsters.h</b> -- back-end for monster implementation. The header file defines an interface that you must implement.
				<li> testworld.lvl -- a very simple level file
				<li> puzzles.o -- This is where the puzzles live. Notice we don't provide the source (that would be spoiling!), but you can create your own by puzzles by referring to the interface in puzzles.h.
				</ul>
				</p>
				
				<p>This is a very large codebase for a 61 series project! Make sure you check out the<a href="#survival">Survival Tips section</a> for ideas about how to make it more manageable.</p>
				

<p><b>Before you program and after you finish each part of the project, *make sure* to test out your implementation in cs61c-world.lvl. It's where you will begin your zany adventure, use your newly implemented skills and learn what you will need in the tough hours to come! (You can also use testworld.lvl to quickly test out some of the simpler implementation details, but its not very exciting).</b></p

				<a name="playing"></a>
				<h3>Playing the Game</h3>
				<p>Once you implement some of the features, you will be able to play the test world. An example transcript of interacting with the game is below:</p>

<p>
<pre id="terminal">
    cs61c-tc@pulsar ~ > <b>./game testworld.lvl</b>
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    Welcome to game, the CS 61C adventure extravaganza!
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    You wake up.
    you are in room #0
    There is an exit to the east
    > go east
    you are in room #1
    There are exits to the north and west
    > dawdle 15
    You dawdle for 15 seconds...
    > ^D
    cs61c-tc@pulsar ~ > 
</pre>
</p>

                <p>However, the real fun is in cs61c-world.lvl, which will run automatically if you run <code>gmake</code> or call <code>./game</code> with no arguments. When you start the game, you should see the following lines:</p>

<p>
<pre id="terminal">
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    Welcome to ./game, the CS 61C adventure extravaganza!  
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    You wake up.
    You are in a cold, concrete-floored room. There are no windows and almost 
    no light. The only thing you can make out is the faint outline of a door 
    to the south.
    There is an exit to the south.
    > 
</pre>
</p>

                <p>If you don't see lines like those above (and instead see something about a button), you have some old framwork files. Update puzzles.c, cs61c-world.lvl, and Makefile from the ~cs61c/proj/01 directory, run <code>gmake clean</code> and be sure it removes the puzzles.o file, and try running <code>gmake</code> again. Post to the newsgroup if you have any further problems.</p>

				<p>Here is a list of commands in the game (some of them not implemented):</p>
				
<p>
<div id="terminal">
<ul>
<li> <code>look</code> -- Look around the current room.
<li> <code>attack <i>monster_name</i></code> -- Attacks the first monster with <i>monster_name</i>. If multiple monsters with the same name are present, successive calls to attack will target the same monster.
<li> <code>dawdle <i>num_seconds</i></code> or <code>wait <i>num_seconds</i></code> -- Wait the given number of seconds of the game time. If it is called with no argument, it will wait for 15 seconds.
<li> <code>quit</code> or <code>exit</code> -- Ends the game.
<li> <code>status</code> -- Prints out the player's status, including hit points and experience.
<li> <code>help</code> -- Prints out all currently available command names.
<li> <code>cast <i>spell</i> <i>target</i></code> -- Cast the spell at the given target.
<li> <code>interact</code> -- Interact with a room's puzzles or people.
<li> <code>go <i>direction</i></code> -- Move around the level. Valid directions are <code>north</code>, <code>south</code>, <code>east</code>, <code>west</code>, <code>up</code>, and <code>down</code>.
</ul>
</div>
</p>

				<a name="assignment"></a>
				<h2>Assignment</h2>
				
				<p>To make sure that everything's ready to go, make sure you can compile and run the game. Do this by running <code>gmake</code> from within the <code>proj1</code> directory. The project will compile and run, but will immediately crash. This is by design; it's trying to load the level file, but <code>load_level()</code> isn't doing a whole lot of anything at the moment. Let's fix that.</p>

				<a name="part0"></a>
				<h3>Part 0: Let there be rooms!</h3>
				<p>To initialize the game world from disk, you need to complete <code>load_level()</code>, found in level.c. The function prototype from level.h is reproduced below:</p>
				
<p><pre id="terminal"><code>room_t *load_level(char *filename);</code></pre></p>
				
				<p>The function should open the file named by <code><i>filename</i></code>, set up <code>room_array[]</code> (a global array of <code>room_t</code> structs), and return a pointer to the starting room. The function will allocate memory on the heap, but because that memory will exist for the duration of the program, there is no need to free any of the memory allocated in <code>load_level()</code>.</p>

				<p>The <code>load_level()</code> function itself is partially implemented in level.c. You will need to fill in the code to perform three tasks:</p>
					
					<ul>
                    <li> <b>Create and initialize the <code>room_array[]</code> data structure.</b> The data structure must be allocated and initialized so that all of the <code>room_t</code> fields, as well as fields of sub-structs, are initialized to NULL or false, as appropriate. The exceptions are <code>room_id</code>, which should be set to the room index from the level file; and </code>mob</code>, which you'll take care of in part 2. <b>You should set the function pointers in the puzzle_t to each be NULL.</b>
                    <li> <b>Room description strings.</b> The <code>description</code> field of each <code>room_t</code> should point to the human readable room description which follows that room's room_id in the level file. The string should not end with a newline. fgets() will return a string with a newline, so overwrite it with a null terminator. <b>Room description strings should NOT include the room number, but instead should begin with the first non-whitespace character after the room number.</b>
					<li> <b>Connect the rooms</b> The <code>exits[]</code> array in each <code>room_t</code> is indexed by the direction enum. Each entry in the array should contain a pointer to the appropriate room if there is an exit in that direction, and locked exits (specified by cant-go lines) should have the <code>locked</code> field set to <code>true</code>. Each <code>exit_t</code> that is not used (does not exist in the game) should keep its <code>dest</code> pointer set to NULL. Note that every exit is meant to be bi-directional: if you <code><i>can-go north 1 2</i></code>, that implies that you can also go south from 2 to 1.
					</ul>
					</p>
					
				<a name="fileformat"></a>
				<h4>Level File Format</h4>
					<p>A level file has the general format shown below, where lines starting with "***" are not literally in the file. An simple example can be found in the testworld.lvl file.

<p>
<pre id="terminal">
<i>NUM_ROOMS</i>

0 <i>This is a room description, printed whenever a player enters the room.</i>
1 <i>This is another description.</i>
2 <i>And another!</i>
*** MORE LINES HERE, UP TO INDEX (NUM_ROOMS - 1) ***

can-go north 0 1       *** AN UNLOCKED EXIT ***
cant-go west 1 2       *** A LOCKED EXIT ***
*** MORE LINES HERE ***
</pre>
</p>	

					<p>A level file must start with an integer number that indicates the total number of rooms.</p>
					<p>Next, there is whitespace (at least two newlines, as in the above example). In the next block each room is described: at the start of each line is a room number, then there is non-newline whitespace, and then the room description string. The description string is ended by a newline. The room description block will always have one line per room, and the room index at the start of each line is guaranteed to be valid (within bounds) but it may be multiple digits.</p>
					
					<p>The room description block is followed by more whitespace (at least two newlines, as above). The final block is the connection block, which describes how rooms should be linked. Each line will start with either "can-go" or "cant-go," which declare an unlocked or locked exit between rooms (respectively). Locks are NOT bi-directional: a "cant-go north 0 1" line will set up a door that is locked from 0 going north, but it will also set up an exit in room 1 going south that is not locked.</p>
                    <p>After either "can-go" or "cant-go" there is non-newline whitespace, followed by a direction name, which is the direction of the exit from the FROM_ROOM to the TO_ROOM. The possible direction names can be found in <code>direction_names[]</code> in level.c. Finally, two numbers are given, separated by non-newline whitespace, which are the FROM_ROOM and TO_ROOM, in that order, which are the room indices to be connected. The indices will always be valid room indices. As an example, the line <code>cant-go north 0 1</code> should connect the north exit of room 0 to room 1, the south exit of room 1 to room 0, and set the <code>locked</code> boolean of room 0's north exit to <code>true</code>. (while leaving the locked boolean of room 1's southern exit alone)
						
					<p>We will not test your solution on level files with repeated, poorly formed, or conflicting connecting statements, e.g. <code>can-go north 0 1</code> followed by <code>can-go north 0 2</code>.</p>

<div id="aside">
<h4>Data Structures to Understand:</h4>
<p>
<ul>
<li> Everything in level.h except for the <code>puzzle_t</code> struct and any <code>puzzle_t</code> fields. Puzzles are only for TA usage.
</ul>
</p>

<h4>Functions to Understand:</h4>
<p>
<ul>
<li> <code>skip_characters()</code> in util.c
<li> <code>member()</code> in util.c
<li> The <code>flip_direction</code> macro in level.h
<li> Provided code blocks in <code>load_level()</code> in level.c.
</ul>
</p>

<h4>Lines of code to add: 25</h4>
</div>
				<a name="part1"></a>
				<h3>Part 1: Get <code>go()</code>-ing!</h3>
				<p>Try loading the game and see what you can do! Not much, huh? Being able to moving around is fun, so why don't you implement the <code>go()</code> function in commands.c. <code>Go()</code> moves the player from room to room by updating the <code>current_room</code> pointer in <code>the_player</code>, a global variable.</p>
				
				<p>Since the <code>go()</code> command is issued in the game just like a command line in the shell, the arguments are passed exactly as in <code>main()</code>. For example, if you type the following when in game:</p>

<p>
<pre id="terminal">
> go north
</pre>
</p>

				<p>The arguments passed to <code>go</code> will be <code>argc = 2, argv = {"go", "north"}</code>.</p>
				
				<p>Your <code>go()</code> function should check to see if the exit in the direction to move is locked, and only move the player if it is not. All commands return the amount of time that command took, and go() is no exception. It should return <code>0</code> if the player attempts to move in a direction where there is no exit, <code>FAILED_MOVE_TIME</code> if there is but it is locked, and <code>MOVE_TIME</code> if the move is successful.</p>

<div id="aside">
<h4>Data Structures to Understand:</h4>
<p>
<ul>
<li> <code>room_t</code> and <code>exit_t</code> in level.h
<li> (optional) <code>commands[]</code> and <code>cmd_entry_t</code> in commands.c
</ul>
</p>

<h4>Functions to Understand:</h4>
<p>
<ul>
<li> (optional) <code>lookup_command</code> in commands.c
<li> (optional) other command functions
<li> (optional) main read-eval-print loop
<li> (optional) <code>tokenizer()</code> in util.c and <code>strtok()</code> the library functions
</ul>
</p>

<h4>Lines of code to add: 35</h4>
</div>

				<a name="part2"></a>
				<h3>Part 2: Monster Mash_t</h3>

				<p>In order for every room in the game to hold a variable number of monsters, you will implement a variable length data structure called a <code>mob_t</code>. This part is relatively self contained within <i>monsters.h</i> and <i>monsters.c</i>. A <code>mob_t</code> is just a dynamic data structure of <code>monster_t</code>s. It supports a function called <code>spawn_new_monster(mob_t *mob)</code> which adds a random <code>monster_t</code> to the <code>mob_t</code>, get the first monster of a particular type with <code>find_monster(mob_t *mob, char *type)</code>. You'll also support <code>append_monster(mob_t *mob, monster_t *monster)</code> and <code>delete_monster(mob_t *mob, monster_t *monster)</code>, which add and remove monsters from mobs.</p>

				<p>But wait, there's more. In order to provide the best data-structure interface ever, you'll also implement a <code>mob_iterator_t</code>, which will provide a convenient interface for outside code to access the monsters in a <code>mob_t</code>.</p>
				
				<p>Check out this snippet, a loop which sets the hp of all monsters in a mob to 0:</p>
				<pre id="source-code">
    monster_t *monster;
    
    // create a new mob_iterator_t
    mob_iterator_t *iter = make_mob_iterator(&amp;the_player.current_room-&gt;mob);
    
    // iterate over every monster in the mob_t
    while((monster = next_monster(iter))) {
        monster-&gt;hp = 0;
    }
    
    // and finally, call delete_mob_iterator() to delete any space
    // that make_mob_iterator may have allocated
    delete_mob_iterator(iter);
				</pre>
				
				<p>Yu are not responsible for what happens if <code>delete_mob_iterator()</code> is never called by outside code. Also, it is assumed that outside code will not add or remove monsters from a <code>mob_t</code> between calls to <code>make_mob_iterator()</code> and <code>delete_mob_iterator()</code>.</p>
				
				<p>Once you're done with with monsters, make sure you update the room initialization code you wrote before. You'll have to do whatever initialization is needed to make sure that the <code>mob</code> in each room starts off in a good state.</p>
				
                <div id="aside">
                <h4>Data Structures to Understand:</h4>
                <p>
                <ul>
                    <li> Even though you won't need to know it's specifics, you should know that <code>monster_t</code> exists, since your data structure will contain <code>monster_t*</code>s.
                    <li> You should understand the interface to <code>mob_iterator_t</code> thoroughly. The fact that you must support it will influence your choice of data structure to use for <code>mob_t</code>.
                    <li> more?
                </ul>
                </p>

                <h4>Functions to Understand:</h4>
                <p>
                <ul>
                    <li> Understand the interface we want you to implement (defined in the header file).
                    <li> In order to implement random monsters, you'll probably want to know about <code>rand()</code>, which lives in stdlib.h. Here's <a href="http://www.cplusplus.com/reference/clibrary/cstdlib/rand.html">a good description</a>.
                </ul>
                </p>

		<h4>Lines of Code: 125</h4>
                </div>

				<a name="part3"></a>
				<h3>Part 3: Magic</h3>
				
				<p>Before you head on to the next implementation section, try playing the game! You should be able to do quite a bit in the game world before you need magic.</p>
				
				<p>You'll come to a point where you need at least one magic spell, so this last implementation section is all about getting the <code>cast</code> command to work to imbue the world with magic.</p>
				
				<p>To get casting to work, you need to implement the <code>get_spell()</code> function in game.c. After a player issues the <code>cast</code> command, <code>get_spell()</code> checks the <code>level_table[]</code> for a spell entry whose name matches the provided string. For example, after receiving the in-game command "cast fireball" we want to check for a spell called "fireball" and, if we find it, return its corresponding function pointer. 
				
				<p>You also need to implement the <code>get_spell_level()</code> function in game.c, which takes the name of a spell being cast and returns the level required to use that spell according to the level table.</p>
				
				<p>Finally, you must implement the <code>cast()</code> function in <code>commands.c</code>. You will need to understand function pointer syntax, since you need to call the function returned by <code>get_spell()</code>. Also, notice that the <code>fireball()</code> spell we have implemented expects arguments like <code>argc = 2</code>, <code>argv = {"fireball", "goblin"}</code>. In other words, it doesn't expect to see <code>"cast"</code> as the first entry in its <code>argv</code> argument, so you shouldn't just past the exact same <code>argc</code> and <code>argv</code> that <code>cast()</code> is called with. Be sure to have checks in case the <code>cast</code> command is issued with an unexpected number of arguments.
				
<div id="aside">
<h4>Data Structures to Understand:</h4>
<p>
<ul>
<li> <code>level_table[]</code> and <code>level_entry</code> in game.c
<li> Check out the function pointer typedef for spells in game.h
</ul>
</p>

<h4>Functions to Understand:</h4>
<p>
<ul>
<li> <code>fireball()</code> in game.c
<li> (optional) <code>damage()</code> in game.c
</ul>
</p>
<h4>Lines of code to add: 20</h4>
</div>

                <a name="survival"></a>
                <h2>Survival tips</h2>
                
                <p>Getting lost in a large codebase is easy, but there are a few things you can do about it.</p>
                
                <p><code>grep</code> is a great tool for finding functions, types, and variables. Don't know where <code>the_player</code> is declared? Just run <tt><b>grep the_player *.h</b></tt> from within the project directory. Nobody is blessed with the natural ability to navigate large projects, and it's one of the most useful skills you can learn.</p>
                
                <p>Make it a habit to read the code which surrounds and makes use of your own. You can learn a lot from context, like how your function will be called, when it will be called, and what it's expected to do. Code reading is an oft overlooked skill, but it can save you a whole mess of time and effort.</p>
                
                <p>Experiment! Don't be afraid to write some C to verify your model of how things work. Any time you're not sure about something, think of a way to verify it from within a little test program. Writing, compiling, and fixing something is the best way to learn. After all, the compiler is the final authority.</p>
                
                <a name="svn"></a>
                <h3>Mini SVN Tutorial</h3>
                
                <p>Version control is a wonderful tool for simplifying development. You can use it to track changes to your files, revert to previous reversions, and figure out <i>exactly</i> where you introduced a bug. For those of you who already know svn, or want to take the time to learn, here's a whirlwind tutorial on making your own repository on the inst machines:</p>

<p>First create a new repository named <i>proj1_repository</i>:</p>
<pre id="terminal">
    cs61c-tc@nova [~] svnadmin create proj1_repository
</pre>

<p>Get the full path of your homedir, and check out a working copy of proj1_repository. Make sure <tt>file:</tt> is followed by <i>three</i> forward slashes. Two because it's a URL, and one for the root directory:</p>
<pre id="terminal">
    cs61c-tc@nova [~] <b>pwd</b>
    <i>(YOUR HOME DIR)</i>
    cs61c-tc@nova [~] <b>svn co file://(YOUR HOME DIR)/proj1_repository proj1_wc</b>
    Checked out revision 0.
</pre>

<p>Copy all the framework files into your working copy, add them via svn, and commit them to the repository:</p>
<pre id="terminal">
    cs61c-tc@nova [~] <b>cd proj1_wc</b>
    cs61c-tc@nova [~/proj1_wc] <b>cp -r ~cs61c/proj/01/* .</b>
    cs61c-tc@nova [~/proj1_wc] <b>svn add *</b>
    A         Makefile
    A         commands.c
    &lt;snip&gt;
    A         util.c
    A         util.h
    cs61c-tc@nova [~/proj1_wc] <b>svn commit -m "Initial check-in of proj1 framework"</b>
    Adding         Makefile
    Adding         commands.c
    <snip>
    Adding         util.c
    Adding         util.h
    Transmitting file data ...................
    Committed revision 1.
</pre>
                <p>Once you've got the repo working, you'll need to know some svn commands to interact with it. Here are some important ones:
                 <i></i>, <i></i>, <i></i>, and <i>commit</i>.</p>
                 
                 <p>
                 <ul>
                 <li> <tt><b>svn add FILE1 [FILE2 ...]</b></tt> &mdash; Marks new files for addition to the repo. They'll only actually get added when you run <i>svn commit</i>
                 <li> <tt><b>svn commit</b></tt> &mdash; Update the repository with your local changes.
                 <li> <tt><b>svn up</b></tt> &mdash; Update your working copy from the repository. You won't need this, since you'll be the only one making changes to it.
                 <li> <tt><b>svn revert FILE1 [FILE2 ...]</b></tt> &mdash; Removes local changes to files, reverting them back to the versions in the repo.
                 <li> <tt><b>svn help</b></tt> &mdash; Lists available commands. For more help on a specific command, do <tt><b>svn help COMMAND_NAME</b></tt>.
                 </ul>
                 </p>
                 
                 <p>It might seem silly to keep a repository just for you, but once you experience the wonders of version control you'll never go back. It will improve your work flow, prevent file deletion disasters, and help you track your changes. It will also make experimentation and exploration easier, since you'll always be able to roll back your changes.</p>

				<a name="submission"></a>
				<h2>Submission</h2>
				<p>All your code should be contained in the provided files, and <code>gmake</code> should build your program without any warnings.</p>

				<p>When you're ready to submit, cd into your project directory, <code>gmake clean</code>, and then <code>submit proj1</code>.</p>
				
				
	
	            <a name="efe"></a>
				<h2>Extra for experts</h2>
	
				<p>Wow, you rock. You built a whole world from raw text files, populated it with dire monsters, and gave our protagonist some spells to fight them. You may have even plumbed the depths of <tt>cs61c-world.lvl</tt>, and discovered the dark secrets lurking within.<p>
				    
				<p>You might think that the fun is over&mdash;but the adventure doesn't have to end here!!! Proj1's unofficial extra for experts is to implement something cool. Seriously, anything. A new spell, a new game feature, or even your own world. Although you can't share code, feel free to post new puzzle.o/puzzle.h and level files to the newsgroup. Go nuts and have fun with it; game programming can be a lot of fun!</p>
				    
				<p>PS As much as I am dying to see all of your awesome new stuff, please keep the extra for experts separate from your submission. This project is going to be hard enough to auto-grade as it is!</p>
			</div>
	</body>
</html>
